package web.suzy.oj.utils;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import web.suzy.oj.shiro.ShiroConstant;

import java.util.Date;

/**
 * YangSuzy 软件工作室
 * 类名: JwtUtils
 * 描述: ---- 待定 -----
 * 功能: ---- 待定 -----
 * ================未完成===============
 *
 * @author YangSuzy
 * Date: 2022/11/14 15:31
 */
//添加微服务后再使用该注解，同时取消此类中的@Value
//@ConfigurationProperties(prefix = "suzyoj.jwt")
@Slf4j(topic = "suzyoj")
@Data
@Component
public class JwtUtils {

    /**
     * token生成所需的私钥
     */
    @Value(value = "${jwt-token-secret}")
    private String secret;

    /**
     * 失效时长
     */
    @Value(value = "${jwt-token-expire}")
    private long expire;

    /**
     * 头部信息
     */
    private String header;

    /**
     * 可刷新的过期时间
     */
    @Value(value = "${jwt-token-fresh-expire}")
    private long checkRefreshExpire;

    @Autowired
    private RedisUtils redisUtils;

    /**
     * 方法名: generateToken
     * 描述: 根据用户ID生成token
     *
     * @param userId
     * @return java.lang.String
     * @date 2022/11/14 15:50
     * @auther YangSuzy
     **/
    public String generateToken(String userId) {
        Date nowDate = new Date();
        //过期时间
        Date expireDate = new Date(nowDate.getTime() + expire * 1000);
        String token = Jwts.builder()
                //设置头部信息参数
                .setHeaderParam("type", "JWT")
                //设置主题
                .setSubject(userId)
                //设置开始时间
                .setIssuedAt(nowDate)
                //设置失效时间
                .setExpiration(expireDate)
                //根据私钥加密签名
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
        //缓存当前token并设置失效时间
        redisUtils.set(ShiroConstant.SHIRO_TOKEN_KEY + userId, token, expire);
        //缓存过期刷新的token
        redisUtils.set(ShiroConstant.SHIRO_TOKEN_REFRESH + userId, "1", checkRefreshExpire);
        return token;
    }

    /**
     * 方法名: getClaimByToken
     * 描述: 解析token串
     *
     * @param token
     * @return io.jsonwebtoken.Claims
     * @date 2022/11/14 15:58
     * @auther YangSuzy
     **/
    public Claims getClaimByToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            log.debug("validate is token error ", e);
            return null;
        }
    }

    /**
     * 方法名: cleanToken
     * 描述: 清空该用户在缓存中的所有token
     *
     * @param uid 用户ID
     * @return void
     * @date 2022/11/14 15:58
     * @auther YangSuzy
     **/
    public void cleanToken(String uid) {
        redisUtils.del(ShiroConstant.SHIRO_TOKEN_KEY + uid, ShiroConstant.SHIRO_TOKEN_REFRESH + uid);
    }

    /**
     * 方法名: hasToken
     * 描述: 检查用户是否有token
     *
     * @param uid 用户ID
     * @return boolean
     * @date 2022/11/14 15:59
     * @auther YangSuzy
     **/
    public boolean hasToken(String uid) {
        return redisUtils.hasKey(ShiroConstant.SHIRO_TOKEN_KEY + uid);
    }

    /**
     * 方法名: isTokenExpired
     * 描述: 检查token是否过期
     *
     * @param expiration
     * @return boolean
     * @date 2022/11/14 15:59
     * @auther YangSuzy
     **/
    public boolean isTokenExpired(Date expiration) {
        return expiration.before(new Date());
    }
}
